package com.cf.conf.core;

import com.cf.aop.AopTargetUtils;
import com.cf.conf.core.formate.Formate;

import com.cf.conf.core.model.Config;
import com.cf.conf.core.model.ConfigMapper;
import com.cf.constant.EnumReturnCode;
import com.cf.exception.BizException;
import com.cf.exception.BizStackException;
import lombok.extern.slf4j.Slf4j;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.data.redis.core.StringRedisTemplate;

import java.lang.reflect.Field;
import java.util.Map;
import java.util.concurrent.ConcurrentHashMap;

/**
 * game-server-PropertyManager
 *
 * @author <a href="2428922347@qq.com">Zhu mingming</a>
 * @info
 * @since 2018/6/8 下午 03:47
 */
@Slf4j
public class PropertyManager {

    @Autowired
    private ConfigMapper configMapper;

    @Autowired
    private ZConfProperty zConfProperty;

    @Autowired
    private StringRedisTemplate redisTemplate;

    private ConcurrentHashMap<String, ValueWrapper> dyField = new ConcurrentHashMap();

    public void registerField(String key, Object bean, Field field) {

        //注册值
        dyField.put(getWatchKey(key), new ValueWrapper(bean, field));

        //设置值
        Map<Object, Object> entries = redisTemplate.opsForHash().entries(getPrefix());
        Object data = entries.get(key);

        //防止redis中缺失，查一遍数据库
        if (data == null)
            data = enSureFromDb(key);

        if (data == null) {
            if (zConfProperty.getErrorOnValueError()) {
                throw new BizException(EnumReturnCode.ERROR.getCode(), "配置信息缺失！" + getPrefix() + ":" + key);
            } else {
                log.info("当前配置为属性缺失不报错！" + "配置信息缺失！" + getPrefix() + ":" + key);
                return;
            }
        }
        try {
            setValue(bean, field, data);
        } catch (Exception e) {
            if (zConfProperty.getErrorOnValueError()) {
                throw new BizStackException(EnumReturnCode.ERROR.getCode(), "设置数据出现异常", e);
            } else {
                log.error("设置数据出现异常", e);
            }
        }
    }

    private Object enSureFromDb(String key) {
        Config config = configMapper.selectByAppAndProfile(zConfProperty.getApp(), zConfProperty.getProfile(), key);
        if (config == null) {
            log.info("数据库中不存在此数据！【{}】", key);
            return null;
        } else {
            log.info("从数据库中获取到数据！【{}】【{}】", key, config.getValue());
            return config.getValue();
        }
    }


    private void setValue(Object bean, Field field, Object data) throws Exception {
        bean = AopTargetUtils.getTarget(bean);
        Class<?> type = field.getType();
        ZValue annotation = field.getAnnotation(ZValue.class);
        Formate formate = (Formate) annotation.formate().newInstance();
        field.setAccessible(true);
        field.set(bean, formate.formate(data.toString(), type));
    }


    private String getPrefix() {
        return zConfProperty.getApp() + "-" + zConfProperty.getProfile();
    }

    private String getPrefix(Config config) {
        return config.getApp() + "-" + config.getProfile();
    }

    private String getWatchKey(String key) {
        return getPrefix() + key;
    }


    public void updateValue(String app, String profile, String key, String value) throws Exception {
        String watchKey = getWatchKey(key);
        ValueWrapper valueWrapper = dyField.get(watchKey);
        if (valueWrapper == null) {
            log.error("动态设置的值未注册！【{}】【{}】【{}】【{}】", app, profile, key, value);
            return;
        }
        Object bean = valueWrapper.getBean();
        Field field = valueWrapper.getField();
        if (bean == null || field == null) {
            log.error("动态设置的值未注册！【{}】【{}】【{}】【{}】", app, profile, key, value);
            return;
        }
        setValue(bean, field, value);
        log.info("动态设置的值成功！【{}】【{}】【{}】【{}】", app, profile, key, value);
    }


}
